import json
import os

from django.http import HttpResponse
from django_celery_beat import models as celery_models
from jinja2 import Template
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response

from fastrunner import models
from fastrunner import tasks
from fastrunner.utils import loader
from fastrunner.utils.decorator import request_log
from fastrunner.utils.host import parse_host
from fastrunner.utils.parser import Format, parse_config

"""运行方式
"""
from FasterRunner.settings import logger, BASE_DIR

@logger.catch
@api_view(['POST'])
@request_log(level='INFO')
def run_api(request):
    """ run api by body
    """
    config_name = request.data.pop('config')
    host_name = request.data.pop("host")
    api = Format(request.data)
    api.parse()
    config = parse_config(api.project, host_name, config_name)
    try:
        summary = loader.debug_api(api.testcase, api.project, config=parse_host(host_name, config))
    except Exception as e:
        logger.error(str(e))
        return Response({'traceback': str(e)}, status=400)
    return Response(summary)


@api_view(['GET'])
@request_log(level='INFO')
def run_api_pk(request, **kwargs):
    """run api by pk and config
    """
    host_name = request.query_params["host"]
    config_name = request.query_params["config"]
    api = models.API.objects.get(id=kwargs['pk'])
    test_case = eval(api.body)
    config = parse_config(api.project.id, host_name, config_name)
    try:
        summary = loader.debug_api(test_case, api.project.id, config=parse_host(host_name, config))
    except Exception as e:
        return Response({'traceback': str(e)}, status=400)
    return Response(summary)


@api_view(['POST'])
@request_log(level='INFO')
def run_api_tree(request):
    """run api by tree
    {
        project: int
        relation: list
        name: str
        async: bool
        host: str
        config:str
    }
    """
    # order by id default
    host_name = request.data["host"]
    config_name = request.data["config"]
    project_id = request.data['project']
    relation = request.data["relation"]
    back_async = request.data["async"]
    name = request.data["name"]

    config = parse_config(project_id, host_name, config_name)
    test_case = []
    for relation_id in relation:
        api = models.API.objects.filter(project__id=project_id, relation=relation_id).order_by('id').values('body')
        for content in api:
            api = eval(content['body'])
            test_case.append(parse_host(host_name, api))

    if back_async:
        tasks.async_debug_api.delay(test_case, project_id, name, config=parse_host(host_name, config))
        summary = loader.TEST_NOT_EXISTS
        summary["msg"] = "接口运行中，请稍后查看报告"
    else:
        try:
            summary = loader.debug_api(test_case, project_id, config=parse_host(host_name, config))
        except Exception as e:
            return Response({'traceback': str(e)}, status=400)
    return Response(summary)


@api_view(["POST"])
@request_log(level='INFO')
def run_testsuite(request):
    """debug testsuite
    {
        project:int
        name: str,
        body: dict
        host: str
    }
    """
    body = request.data["body"]
    project_id = request.data["project"]
    name = request.data["name"]
    host_name = request.data["host"]
    config_name = request.data["config"]

    test_case = []
    config = parse_config(project_id, host_name, config_name)

    for test in body:
        test = loader.load_test(test, project=project_id)
        if "base_url" in test["request"].keys():
            config = test
            continue
        test_case.append(parse_host(host_name, test))

    summary = loader.debug_api(test_case, project_id, name=name, config=parse_host(host_name, config))
    return Response(summary)


@api_view(["POST"])
@request_log(level='INFO')
def run_testsuite_pk(request, **kwargs):
    """run testsuite by pk
        {
            project: int,
            name: str,
            host_name: str,
            config_name:str
            testDataExcel: str
            testDataSheet: str
        }
    """
    pk = kwargs["pk"]
    test_list = models.CaseStep.objects.filter(case__id=pk).order_by("step").values("body")
    project_id = request.data.get("project")
    name = request.data.get("name")
    host_name = request.data.get("host")
    config_name = request.data.get("config")
    back_async = request.data.get("async")
    report_name = request.data.get("reportName","")
    source = request.data.get("source","")
    test_data = None
    if request.data.get("excelTreeData"):
        test_data = tuple(request.data["excelTreeData"])

    test_case = []
    config = parse_config(project_id, host_name, config_name)

    for content in test_list:
        body = eval(content["body"])
        if "base_url" in body["request"].keys():
            config = eval(models.Config.objects.get(name=body["name"], project__id=project_id).body)
            continue

        test_case.append(parse_host(host_name, body))

    try:
        if isinstance(back_async, str):
            back_async = False
            if str(back_async).lower() == "true": back_async = True
        if back_async:
            tasks.async_debug_test.delay(test_case, project_id, name=name, report_name=report_name, config=parse_host(host_name, config), test_data=test_data)
            summary = loader.TEST_BACK_ASYNC
        else:
            summary = loader.debug_api(test_case, project_id, name=name, config=parse_host(host_name, config), test_data=test_data, report_name=report_name)

        if source == "jenkins":  # 直接返回html报告
            template_file = os.path.join(BASE_DIR, "templates/orgin_report_template.html")
            template_content = open(template_file, "r").read()
            rendered_content = Template(
                template_content,
                extensions=["jinja2.ext.loopcontrols"]
            ).render(summary)
            return HttpResponse(rendered_content)
        return Response(summary)
    except Exception as e:
        logger.error(str(e))
        return Response({'traceback': str(e)}, status=400)


@api_view(["POST"])
@request_log(level='INFO')
def run_casestep_pk(request, **kwargs):
    """run casestep by pk
        {
            project: int,
            name: str,
            host: str,
            testDataExcel: str
            testDataSheet: str
        }
    """
    pk = kwargs["pk"]
    test_list = models.CaseStep.objects.filter(id=pk).order_by("step").values("body")
    project_id = request.data["project"]
    host_name = request.data["host"]
    config_name = request.data["config"]
    test_case = []
    config = parse_config(project_id, host_name, config_name)

    for content in test_list:
        body = eval(content["body"])

        if "base_url" in body["request"].keys():
            config = eval(models.Config.objects.get(name=body["name"], project__id=project_id).body)
            continue

        test_case.append(parse_host(host_name, body))

    try:
        summary = loader.debug_api(test_case, project_id, config=parse_host(host_name, config))
    except Exception as e:
        logger.error(str(e))
        return Response({'traceback': str(e)}, status=400)
    return Response(summary)


@api_view(['GET'])
@request_log(level='INFO')
def run_schedule_test(request, **kwargs):
    try:
        pk = kwargs["pk"]
        test_case = celery_models.PeriodicTask.objects.get(id=pk)
        run_args = json.loads(test_case.args)
        run_kwargs = json.loads(test_case.kwargs)
        # run_kwargs["strategy"] = '始终发送'
        tasks.schedule_debug_suite.delay(*run_args, **run_kwargs)
        return Response(status=status.HTTP_204_NO_CONTENT)
    except Exception as e:
        logger.error(str(e))
        return Response({'traceback': str(e)}, status=400)


@api_view(['POST'])
@request_log(level='INFO')
def run_suite_tree(request):
    """run suite by tree
    {
        project: int
        relation: list
        name: str
        async: bool
        host: str
    }
    """
    # order by id default
    try:
        project_id = request.data['project']
        host_name = request.data["host"]
        config_name = request.data["config"]
        relation = request.data["relation"]  # relation=[1, 27, 31]
        report_name = request.data["name"]
        back_async = request.data["async"]

        test_sets = []
        suite_list = []
        config_list = []
        # 遍历节点
        for relation_id in relation:
            # case_list 节点下的用例列表
            case_list = list(models.Case.objects.filter(project__id=project_id, relation=relation_id).order_by('id').values('id', 'name'))
            suite_list = suite_list + case_list
            for case in case_list:
                # step_list 用例下的测试步骤列表
                step_list = models.CaseStep.objects.filter(case__id=case["id"]).order_by("step").values("body")

                testcase_list = []  #

                # 遍历测试步骤
                for step in step_list:
                    body = eval(step["body"])
                    if "base_url" in body["request"].keys():
                        config = eval(models.Config.objects.get(name=body["name"], project__id=project_id).body)
                        continue
                    testcase_list.append(parse_host(host_name, body))

                # [[{scripts}, {scripts}], [{scripts}, {scripts}]]
                config = parse_config(project_id, host_name, config_name)
                config_list.append(parse_host(host_name, config))
                test_sets.append(testcase_list)

        if back_async:
            tasks.async_debug_suite.delay(test_sets, project_id, suite_list, report_name, config_list)
            summary = loader.TEST_NOT_EXISTS
            summary["msg"] = "用例运行中，请稍后查看报告"
        else:
            summary = loader.debug_suite(test_sets, project_id, suite_list, config_list)
        return Response(summary)
    except Exception as e:
        logger.error(str(e))
        return Response({'traceback': str(e)}, status=400)


@api_view(["POST"])
@request_log(level='INFO')
def run_test(request):
    """debug single test
    {
        host: str
        body: dict
        project :int
        config: null or dict
    }
    """
    body = request.data["body"]
    config = request.data.get("config", None)
    project = request.data["project"]
    host = request.data["host"]

    if host != "请选择":
        host = models.HostIP.objects.get(name=host, project=project).value.splitlines()

    if config:
        config = eval(models.Config.objects.get(project=project, name=config["name"]).body)

    summary = loader.debug_api(parse_host(host, loader.load_test(body)), project, config=parse_host(host, config))
    return Response(summary)
